Skip to content

Mark merge conflict comments as resolved once the conflict is fixed - #20

Open
diedexx wants to merge 5 commits into
mainfrom
resolve-comment
Open

Mark merge conflict comments as resolved once the conflict is fixed#20
diedexx wants to merge 5 commits into
mainfrom
resolve-comment

Conversation

@diedexx

@diedexx diedexx commented Jul 28, 2026

Copy link
Copy Markdown
Member

Summary

The merge conflict check already removes the merge conflict label once a PR stops conflicting, but the comment explaining the conflict stayed visible. That left stale, misleading noise on PRs that were no longer conflicting.

This collapses that comment as RESOLVED once the conflict is gone, which is the same result as using the "Hide comment" UI manually.

While working on this, zizmor flagged a pre-existing high severity script injection vulnerability in the "Create label" step, which is fixed here as a separate commit.

Changes

Security fix (39ad453)

  • The "Create label if it doesn't exist" step interpolated the caller-controlled ${{ inputs.dirtyLabel }} directly into an actions/github-script body. Since this workflow is reusable and is typically called from pull_request_target with a write-scoped token, a crafted label name could break out of the string literal and execute arbitrary code in the calling repository. The input is now passed through the environment and read via process.env, so it is always treated as inert data.

Auto-resolve comments (a244059)

  • Mark the commentOnDirty comment as resolved via the GraphQL minimizeComment mutation once a PR is no longer conflicting.
  • Only comments which were authored by this workflow, are not already minimized, and whose body matches commentOnDirty exactly are minimized.
  • Reuses the check step's existing prDirtyStatuses output to decide which PRs are clean, so no extra merge state queries are needed.
  • Added timeout-minutes: 20 as a last line of defense against a runaway job.
  • Declared permissions explicitly: permissions: {} at workflow level, with the job opting in to only issues: write and pull-requests: write. This narrows the token compared to the previous implicit defaults.

diedexx and others added 3 commits July 28, 2026 10:17
The "Create label if it doesn't exist" step interpolated the caller-controlled
`dirtyLabel` input directly into the `actions/github-script` body. Because this
workflow is reusable and is typically called from a `pull_request_target`
trigger, the step runs with a write-scoped token, so a label name crafted to
break out of the surrounding string literal could execute arbitrary code in the
context of the calling repository.

Pass the input through the environment and read it via `process.env` instead, so
the value is always treated as inert data rather than as part of the script.

Reported by zizmor as template-injection (high severity).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The merge conflict check already removes the dirty label when a conflict is
resolved, but the comment explaining the conflict stayed visible, leaving stale
noise on the PR. Minimize it as RESOLVED instead, which collapses it the same way
the "Hide comment" UI does.

The check step's existing `prDirtyStatuses` output is reused to determine which
PRs are no longer conflicting, so no extra merge state queries are needed.

Only comments which were authored by this workflow, are not already minimized,
and whose body matches `commentOnDirty` exactly are minimized, so human comments
and unrelated bot comments are never hidden.

Pagination stops when the API claims a further page without advancing the cursor,
which would otherwise loop forever, and the job now has an explicit timeout as a
second line of defense. Permissions are declared explicitly and default to none
at the workflow level, so the job only gets the scopes it actually needs.

The behavior is opt-out via the new `minimizeCommentOnClean` input.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…cope

Code review raised two assumptions worth recording. Minimizing relies on an
exact match against `commentOnDirty`, so editing that input leaves comments which
were posted with the previous wording visible instead of collapsing them. Mention
this in the README so the behavior is not surprising.

Also note that `viewerDidAuthor` filters on the identity behind the token, which
is the default GITHUB_TOKEN here, so a future change passing a PAT or app token
to that step would widen which comments get minimized.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the reusable merge-conflict-check workflow to reduce stale PR noise by auto-collapsing prior “merge conflict” bot comments after conflicts are resolved, and hardens the workflow against script injection in a label-creation step.

Changes:

  • Adds an opt-out input (minimizeCommentOnClean) to minimize the prior commentOnDirty comment as RESOLVED when a PR becomes conflict-free.
  • Fixes a script-injection vector by passing caller-controlled inputs via env and reading them through process.env in actions/github-script.
  • Narrows token permissions (workflow-level permissions: {}, job-level least-privilege) and adds a job timeout safety net.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
README.md Documents the new minimizeCommentOnClean input and its behavior.
.github/workflows/reusable-merge-conflict-check.yml Implements comment minimization logic, adds explicit permissions + timeout, and fixes input interpolation injection risk.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread README.md
Comment thread .github/workflows/reusable-merge-conflict-check.yml Outdated
Comment thread .github/workflows/reusable-merge-conflict-check.yml Outdated
diedexx and others added 2 commits July 28, 2026 14:11
The conflict comment is usually one of the most recent comments on a PR, but the
scan walked the comment history from the oldest comment forward, so PRs with a
long history needed several requests to reach it.

Walk the comments backwards instead, which normally finds the comment in the
first page. The endless loop guard now tracks `startCursor`/`hasPreviousPage`
accordingly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@diedexx
diedexx marked this pull request as ready for review July 28, 2026 12:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants